Project Report

Abstract

In Sports Analytics, there has been evergoing research on whether the market price of a Player is overpriced or not. Various attributes factor this analysis like Age, Position, games/minutes played, player efficiency rating etc. This project aims to explore the dataset of NBA players based on salary and their season statistics for the year 2016-2017. The aim of this project is to generate a regression model that can be used to predict player’s salary which can help in determining the accuracy of player’s salary.

NBA

Introduction

Prediction method based on regression model can be defined as: Regression models predict a value of Y variable from the dataset for any other known value or values X variables from the dataset. Prediction of regression model is based on:

  • y-intercept: Dependent variable

  • x-intercept: Independent variable

Prediction requires consideration of good attributes which depends on the type of variables considered for generating a model. This is important as the factors might affect the prediction of salary significantly.

The coefficients in the equation have the relationship between each independent variable and dependent variable. While this is true, also entering values for independent variables into the equation for predicting mean value is achievable for dependent variable.

This is needed for generating unbiased predictions. Getting predictions precise is done when the observed values cluster are close to the predicted values. For solving this issue we can consider hypothesis

NBA dataset is a good example for solving the task on prediction as it provides relevant quantitative variables like Age, PER, FPG, G, TS, AST and also some qualitative variables like Pos, Tm etc.

The dataset will be statistically checked to determine if assumptions are met to determine if Points Scored(PPG) is a factor that affects the prediction significantly i.e study will be needed to test whether the mean (PPG) differs and is a factor that is affecting the salary significantly.

All statistical analyses will be performed using R (software version 4.1.2).

Hypotheses

Null Hypothesis (H0):Mean PPG has no impact on salary \[ H_0: \mu_1 = \mu_1 = \mu_3 \] Alternative hypothesis (Ha): Atleast some difference in Mean PPG impact salary \[ H_A: Some~ \mu~ is \ne \]

Design/Methods

  • The approach for designing our model will be based on our dataset and the variables that we choose.

  • The objective of our study is to build a regression model and evaluate it based on our NBA dataset variables and player’s season_stats dataset.

  • Designing the method for prediction analysis requires selection of variables based on their correlation strength with the dependent variable.

Required packages

  • Following are the packages required with their use:

    • tidyverse = Allows for data manipulation and works in harmony with other packages as well

    • plotly = graphical representation in r

    • rstatix = performing statistical tests

    • data.table = Dataframe Enhancement Tool

    • corrplot = Generation of Correlation plots

    • PerformanceAnalytics = Performance and Prediction Analytics Package

    • GGally = A ggplot2 extension

install.packages(“rsconnect”)

Data Preparation

Plotting First DataSet

Plotting Second Dataset

Data Component

  • Column “Pos”: Position at which the player is assigned or plays at.
  • Column “PTS”: Points scored by the player
  • Column “Tm”: Name of Team played by the player for
  • Column “G”: No. of Games played by the player
  • Column “MP”: Minutes played by the player
  • Column “PER”: Performance Efficiency Rate for the player
  • Column “AST”: Assists made by the player
  • Column “TRB”: Total Rebounds by the Player
  • Column “TOV”: Turnovers made by the player
  • Column “BLK”: Block made by the player
  • Column “STL”: Steals made by the player

Added Columns

  • Column “PPG”: Points scored by the player per Game
  • Column “MPG”: Minutes played by the player per Game
  • Column “APG”: Assists made by the player per Game
  • Column “RPG”: Rebounds Percentage per Game
  • Column “TOPG”: Turnover Percentage per Game
  • Column “BPG”: Block Percentage per Game
  • Column “SPG”: Steal Percentage per Game

Obtaining the types of Data available in season_salary dataset.

This dataset contains 573 rows for columns of X(player_id), Player(Name), Team(Tm) and Season Salary(Season17_18).

## 'data.frame':    573 obs. of  4 variables:
##  $ X          : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Player     : chr  "Stephen Curry" "LeBron James" "Paul Millsap" "Gordon Hayward" ...
##  $ Tm         : chr  "GSW" "CLE" "DEN" "BOS" ...
##  $ season17_18: num  34682550 33285709 31269231 29727900 29512900 ...

Obtaining the types of Data available in player_stats dataset.

This dataset contains 24691 rows for 53 columns with major features being, Position(Pos), Age, Games Played(G), Points Scored(Pts), Minutes Played(MP) etc.

## 'data.frame':    24691 obs. of  53 variables:
##  $ X     : int  0 1 2 3 4 5 6 7 8 9 ...
##  $ Year  : int  1950 1950 1950 1950 1950 1950 1950 1950 1950 1950 ...
##  $ Player: chr  "Curly Armstrong" "Cliff Barker" "Leo Barnhorst" "Ed Bartels" ...
##  $ Pos   : chr  "G-F" "SG" "SF" "F" ...
##  $ Age   : int  31 29 25 24 24 24 22 23 28 28 ...
##  $ Tm    : chr  "FTW" "INO" "CHS" "TOT" ...
##  $ G     : int  63 49 67 15 13 2 60 3 65 36 ...
##  $ GS    : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ MP    : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ PER   : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ TS.   : num  0.368 0.435 0.394 0.312 0.308 0.376 0.422 0.275 0.346 0.362 ...
##  $ X3PAr : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ FTr   : num  0.467 0.387 0.259 0.395 0.378 0.75 0.301 0.313 0.395 0.48 ...
##  $ ORB.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ DRB.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ TRB.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ AST.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ STL.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ BLK.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ TOV.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ USG.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ blanl : logi  NA NA NA NA NA NA ...
##  $ OWS   : num  -0.1 1.6 0.9 -0.5 -0.5 0 3.6 -0.1 -2.2 -0.7 ...
##  $ DWS   : num  3.6 0.6 2.8 -0.1 -0.1 0 1.2 0 5 2.2 ...
##  $ WS    : num  3.5 2.2 3.6 -0.6 -0.6 0 4.8 -0.1 2.8 1.5 ...
##  $ WS.48 : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ blank2: logi  NA NA NA NA NA NA ...
##  $ OBPM  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ DBPM  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ BPM   : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ VORP  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ FG    : int  144 102 174 22 21 1 340 5 226 125 ...
##  $ FGA   : int  516 274 499 86 82 4 936 16 813 435 ...
##  $ FG.   : num  0.279 0.372 0.349 0.256 0.256 0.25 0.363 0.313 0.278 0.287 ...
##  $ X3P   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ X3PA  : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ X3P.  : num  NA NA NA NA NA NA NA NA NA NA ...
##  $ X2P   : int  144 102 174 22 21 1 340 5 226 125 ...
##  $ X2PA  : int  516 274 499 86 82 4 936 16 813 435 ...
##  $ X2P.  : num  0.279 0.372 0.349 0.256 0.256 0.25 0.363 0.313 0.278 0.287 ...
##  $ eFG.  : num  0.279 0.372 0.349 0.256 0.256 0.25 0.363 0.313 0.278 0.287 ...
##  $ FT    : int  170 75 90 19 17 2 215 0 209 132 ...
##  $ FTA   : int  241 106 129 34 31 3 282 5 321 209 ...
##  $ FT.   : num  0.705 0.708 0.698 0.559 0.548 0.667 0.762 0 0.651 0.632 ...
##  $ ORB   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ DRB   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ TRB   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ AST   : int  176 109 140 20 20 0 233 2 163 75 ...
##  $ STL   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ BLK   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ TOV   : int  NA NA NA NA NA NA NA NA NA NA ...
##  $ PF    : int  217 99 192 29 27 2 132 6 273 140 ...
##  $ PTS   : int  458 279 438 63 59 4 895 10 661 382 ...

Data Cleaning

The filteration technique was used to obtain a dataset for player’s stats based on the year: 2016

There was a need to mutate features like MPG, PPG, APG etc. to perform regression analysis based on per Game.

Filtered data can be viewed here as:

Merging Data

Our merged data betwen filtered_2016 dataset and season_salary dataset can be viewed here.

Correlation check

Correlation check No1

Following plot is for checking correlation

Correlation check No2

Following plot is for checking correlation

Correlation Analysis

Table shows the correlation value for the following variables

## filter_sal        PPG        MPG       TOPG        RPG        PER        SPG 
##  1.0000000  0.6806714  0.6149170  0.5301139  0.5333931  0.5454683  0.4429916 
##        APG 
##  0.3883572

Correlation strength is: PPG > MPG > TOPG > RPG > PER > SPG > APG

The interesting part of this is that the number of turnovers players make in direct correlation to their salary, and the relationship shows a positive correlation.

The interpretation can be demonstrated in the following way:

The more turnovers they make will result in increased involvement and outcome will be more ball movements in a game.

This way, we can claim that the players who make more turnovers, are directly or at important to their team. This can be expressed as “agressiveness”.

This assumption will be used in place of the duration for which player holds/contains ball in possession in a game.

Data Visualization

DataSet plotting

Following plot shows the Boxplot distribution of Points scored per game. We can see multiple outliers in this graph. This graph display median value as 8. And, the outliers are accumulated near the range 25-30.

Interactive Plot

When hovered over the highest valued data, we receive the following information for the data point.

  • The most paid player with $34,682,550 is
    • Stephen Curry
    • Scores 30.063 PPG
    • Plays for Team: Golden State Warriors

Simple Linear Regression Model

Scatter plot with regression line

Analysis

Regression Analysis

## 
## Call:
## lm(formula = filter_sal ~ ., data = salary_regression)
## 
## Coefficients:
## (Intercept)          MPG          PPG          APG          RPG         TOPG  
##    -2335560       -64693       998724      1142968       839990     -3937386  
##         BPG          SPG  
##     1865318       836451
  • Statistical Insights
    • Salary rises by $998,724 per year due to the effect of Points Per Game by Player
    • More Assist Per Game also results in increase in Salary

Trust Factor on Player(by Coach): Depends on Number of turnovers they make..

Prallel Slope Model

Scatter plot coloured by how many turnovers they make

This proves the Assumption that the player who makes more number of turnovers will get paid higher or will receive increase in Salary.

Modeling & Model_fit Results

Finding Salary for an average player is necessary for determining the per salary increase after taking Trusted and Agressiveness factors into consideration.

An average player receives the following Salary per Season

## [1] 8271766

Here we are generating a Multiple Regression model based on Factors like Trusted and Agressiveness.

We can determine the model_fit by obtaining the coefficients of the features:

## 
## Call:
## lm(formula = filter_sal ~ Trusted * Agressiveness, data = salary_regression)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -13221467  -3611877  -1639386   3916099  20950162 
## 
## Coefficients:
##                             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                  3973906     518474   7.665 1.66e-13 ***
## TrustedYes                   4609276    1034546   4.455 1.12e-05 ***
## AgressivenessYes             1607136    1595830   1.007   0.3146    
## TrustedYes:AgressivenessYes  3542071    1916651   1.848   0.0654 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 6579000 on 363 degrees of freedom
## Multiple R-squared:  0.3107, Adjusted R-squared:  0.305 
## F-statistic: 54.55 on 3 and 363 DF,  p-value: < 2.2e-16

Obtaining Coefficients for the features.

##                 (Intercept)                  TrustedYes 
##                     3973906                     4609276 
##            AgressivenessYes TrustedYes:AgressivenessYes 
##                     1607136                     3542071
  • Results

    • There is a direct correlation based on trust and salary increase.

    • This leads to more play time allowed by coach and increase in probability to score more Points per Game(PPG).

    • The salary will increase by $311,416.

Analysis & conclusion

Prediction Function

Let’s try to predict salary for the Most Valuable Player for the year 2016. The Professional Basketballer “Russel Westbrook” played for the team Oklahoma City Thunder and has a sensational season both in Regular and Playoffs Season as well.

RB

The statistics for his performance was referenced by the website Basketball Reference: Russel Westbrook.

Russel Westbrook’s Statistics for the year was:

  • Points per Game (PPG): 31.6

  • Minutes played per Game (MPG): 34.6

  • Turnovers per Game (TOPG): 5.4

Conclusion

Based on the stats for Russel Westbrook, we generate a prediction_fit model and compute the Prediction Salary.

## [1] "PPG:31.6,MPG:34.6,TOPG:5.4 ==> Expected Salary for player: $25,707,363"
  • According to my prediction model, he will get $25,707,363 next season.

  • The Official Salary Russel Westbrook received in his next season was: $28,530,608.

  • This resulted with a 93 percent accuracy for our prediction model.

Summary

Our Assessment Study of this Dataset provided many deep insights about the dataset. Based on our study:

  • We were able to clean the data and remove null values or irrelevant variables from the data.
  • We were able to Mutate columns for two datasets which provided us with a better dataset to pursue our study on.
  • We were able to check different types of datatypes present in our dataset.
  • We figured out how many variables are quantitative variables and how many variables are categorical variables.
  • Based on quantitative variables, we were able to perform Exploratory Data Analysis using histogram plot, scatterplot and obtain deeper insights of our data.
  • Based on categorical variables we were able to split our datasets on levels using factors variables in variables like Aggressiveness, and Trusted etc.
  • We were able to determine influential variables in our data.
  • We were able to determine a trend on how higher played players(players with higher salaries) tend to score more points per Game.
  • We were able to determine correlation between variables and how they impact the player’s salary.
  • Through Hypothesis Testing, We were able to prove how highest correlated variable PPG has a significant impact on player’s Salary and leads to increase in salary.
  • Through model fitting, we successfully achieved the task of generating prediction based on highly influential variables.
  • We were able to achieve an outstanding accuracy rate of 93 percent using this model.
  • We also were able to answer the assumptions of how a Coach’s trust factor for a player increases Points scored per Game by a player and is able to generate more turnovers during the game.
  • These assumptions also provided us with a new trend on determining significant impact (increase) in player’s Salary.
  • Finally for checking the working of our prediction model, we Performed prediction for the Most Valuable Player for the year 2016: Russel Wetbrook.

Personal Information

Amogh Singh

I am a Graduate Student at Clemson University perusing his Master’s degree in Computer Science. I have completed Bachelor’s in Computer Engineering from Mumbai, India and have developed deep interest in Data Visualization after my Internship on creating dashboards using Streamlit package in Python. This was one of the key reasons for completing the course on Statistical Computing in R which helped me in learning EDA and Visualization along with basics of Hypothesis testing in R.

In the last years, I have learned working with datasets with quantitative and qualitative variables. However, this project gave me insights on prediction modelling and the capability it demonstrates in making the analysis in bettering perspective over the field of research.

Profile

Appendix

#LOADING PACKAGES
library(data.table) #Enhanced dataframe
library(corrplot)   #For plotting correlation plot
library(GGally)     #Alternative Package(An Extension) for ggplot2
library(tidyverse)  #Package that we can use for data analysis
library(PerformanceAnalytics) # Package for Performance, Prediction Analysis
library(plotly) #For improving Graphics on plots
library(rstatix) #Package for performing statistical tests

# Dataset is read
##First dataset
season_salary <- 
  read.csv("NBA_season1718_salary.csv")
season_salary

##Second dataset
player_stats <- read.csv("Seasons_Stats.csv")
player_stats

#displaying datatypes of variables
#datatypes for dataset 1
str(season_salary)

#datatypes for dataset 2
str(player_stats)

#Filtering dataset for receving datapoints for the year: 2016.
#Selecting relevant variables like Year, G, PER, FG, PTS etc.
#Mutating columns named MPG, RPG, PPG, APG, TOPG, BPG, SPG for further analysis
filtered_2016 <- 
  player_stats %>% filter(Year == 2016) %>% 
  select(Year:G, MP, PER, FG:PTS) %>% 
  distinct(Player, .keep_all = TRUE) %>% 
  mutate(MPG = MP/G, PPG = PTS/G, APG = AST/G, 
         RPG = TRB/G, TOPG = TOV/G, BPG = BLK/G, 
        SPG = STL/G)

# Performing full join using merge function for Joining filtered_2016 dataset and season_salary dataset based on common variable "Player".
salary_new <- merge(filtered_2016, season_salary, by.x = "Player", by.y = "Player")
# Renaming a column for salary
names(salary_new)[40] <- "filter_sal"
#Deleting unwanted column
salary_new <- salary_new[-39]

#Generating correlation plot for salary with other influential variables
#to check whether these variables have correlation.
corrplot(cor(salary_new %>% 
               select(filter_sal, MPG:SPG, 
                      Age, PER, contains("%")), 
             use = "complete.obs"), 
         method = "number",type = "upper")

## Plotting scatterplot matrix for correlation for features with salary variables.
# Made use of ggpairs function.
cor_salary_new <- 
  salary_new %>% 
  select(filter_sal, PPG, MPG, TOPG, RPG, PER, SPG, APG)
ggpairs(cor_salary_new)

#Correlation table
cor(cor_salary_new)[,"filter_sal"]

#Generation of Interactive plot for plotting influence of salary received by the player over points scored per game.
#plotly function is used
#hoverinfo argument provides useful technique in generating a plot with dynamic nature. Extremely useful for plotting real-time data.
names(salary_new)[5] <- "Team"
plot_ly(data = salary_new, x = ~filter_sal, y = ~PPG, color = ~Team,
        hoverinfo = "text",
        text = ~paste("Player: ", Player,
                      "<br>Salary: ", format(filter_sal, big.mark = ","),"$",
                      "<br>PPG: ", round(PPG, digits = 3),
                      "<br>Team: ", Team)) %>% 
  layout(
    title = "Salary vs Point Per Game",
    xaxis = list(title = "Player's Salary in USD"),
    yaxis = list(title = "Point per Game for Player")
  )

#Plotting scatterplot of regression Model for salary variable on Points Scored per Game to see variance in the graph
salary_new %>% 
  ggplot(aes(x = filter_sal, y = PPG)) + 
  geom_point() + 
  geom_smooth(method = "lm")

#For determining the effect of Trust on Turnovers.
#Obtaining average for MPG feature using mean function
avg.minutes <- mean(salary_regression$MPG)
#Obtaining average for TOPG feature using mean function
avg.turnover <- mean(salary_regression$TOPG)
#Converting categorical variable into factors for Yes and No values
salary_regression$Trusted <- as.factor(ifelse(salary_regression$MPG >= avg.minutes, "Yes", "No"))
#Converting categorical variable into factors for Yes and No values
salary_regression$Agressiveness <- as.factor(ifelse(salary_regression$TOPG >= avg.turnover, "Yes", "No"))
#Printing first 10 rows of the dataset
head(salary_regression)

# Generating regression plot to determine any difference in salary based on Agressiveness
salary_regression %>% 
  ggplot(aes(x = filter_sal, y = PPG, colour = Agressiveness)) + 
  geom_point() + 
  geom_smooth(method="lm")

#Getting average player's salary by finding the mean for all players
mean_salary <- mean(salary_regression$filter_sal)
mean_salary

#Fitting a multiple regression model for salary based on Trusted and Agressiveness
trust_lm <- lm(formula = filter_sal ~ Trusted * Agressiveness, data=salary_regression)
#Plotting summary table for our regression model
summary(trust_lm)

# Coefficients Table
coef(trust_lm)

#Building a prediction function for predicting value based on PPG, MPG, TOPG.
# Printing output value for our function
salary_prediction <- function(m, point, minutes, turn_over){
  pre_new <- predict(m, data.frame(PPG = point, MPG = minutes, TOPG = turn_over))
  msg <- paste("PPG:", point, ",MPG:", minutes, ",TOPG:", turn_over, " ==> Expected Salary for player: $", format(round(pre_new), big.mark = ","), sep = "")
  print(msg)
}

# Fitting values for obtaining output
model <- lm(formula = filter_sal ~ PPG + MPG + TOPG, data = salary_regression)
salary_prediction(model, 31.6, 34.6, 5.4)

Acknowledgement

  • Clemson University School of Computing.

  • Prof. Ellen Breazel, Teacher in STAT-6020 Intro to Statistical Computing - Spring 2022 at Clemson University.

LS0tDQp0aXRsZTogIkFuYWx5c2lzIG9mIE5CQSBTYWxhcnkgUHJlZGljdGlvbiINCmF1dGhvcjogIkFtb2doIFNpbmdoIg0KRGF0ZTogMDUvMDMvMjAyMg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIGVjaG89RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobz1UUlVFLCBlcnJvcj1GQUxTRSkNCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKQ0KYGBgDQoNCg0KIyBQcm9qZWN0IFJlcG9ydCB7LnRhYnNldH0NCg0KIyMgQWJzdHJhY3QNCkluIFNwb3J0cyBBbmFseXRpY3MsIHRoZXJlIGhhcyBiZWVuIGV2ZXJnb2luZyByZXNlYXJjaCBvbiB3aGV0aGVyIHRoZSBtYXJrZXQgcHJpY2Ugb2YgYSBQbGF5ZXIgaXMgb3ZlcnByaWNlZCBvciBub3QuIFZhcmlvdXMgYXR0cmlidXRlcyBmYWN0b3IgdGhpcyBhbmFseXNpcyBsaWtlIEFnZSwgUG9zaXRpb24sIGdhbWVzL21pbnV0ZXMgcGxheWVkLCAgcGxheWVyIGVmZmljaWVuY3kgcmF0aW5nIGV0Yy4gVGhpcyBwcm9qZWN0IGFpbXMgdG8gZXhwbG9yZSB0aGUgZGF0YXNldCBvZiBOQkEgcGxheWVycyBiYXNlZCBvbiBzYWxhcnkgYW5kIHRoZWlyIHNlYXNvbiBzdGF0aXN0aWNzIGZvciB0aGUgeWVhciAyMDE2LTIwMTcuIFRoZSBhaW0gb2YgdGhpcyBwcm9qZWN0IGlzIHRvIGdlbmVyYXRlIGEgcmVncmVzc2lvbiBtb2RlbCB0aGF0IGNhbiBiZSB1c2VkIHRvIHByZWRpY3QgcGxheWVyJ3Mgc2FsYXJ5IHdoaWNoIGNhbiBoZWxwIGluIGRldGVybWluaW5nIHRoZSBhY2N1cmFjeSBvZiBwbGF5ZXIncyBzYWxhcnkuDQoNCjxjZW50ZXI+DQohW05CQV0oTkJBXzJLMTYuanBnKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCg0KDQojIyBJbnRyb2R1Y3Rpb24gey50YWJzZXR9DQoNClByZWRpY3Rpb24gbWV0aG9kIGJhc2VkIG9uIHJlZ3Jlc3Npb24gbW9kZWwgY2FuIGJlIGRlZmluZWQgYXM6IFJlZ3Jlc3Npb24gbW9kZWxzIHByZWRpY3QgYSB2YWx1ZSBvZiBZIHZhcmlhYmxlIGZyb20gdGhlIGRhdGFzZXQgZm9yIGFueSBvdGhlciBrbm93biB2YWx1ZSBvciB2YWx1ZXMgWCB2YXJpYWJsZXMgZnJvbSB0aGUgZGF0YXNldC4gDQpQcmVkaWN0aW9uIG9mIHJlZ3Jlc3Npb24gbW9kZWwgaXMgYmFzZWQgb246DQoNCiogX195LWludGVyY2VwdDogRGVwZW5kZW50IHZhcmlhYmxlX18NCg0KKiBfX3gtaW50ZXJjZXB0OiBJbmRlcGVuZGVudCB2YXJpYWJsZV9fDQoNClByZWRpY3Rpb24gcmVxdWlyZXMgY29uc2lkZXJhdGlvbiBvZiBnb29kIGF0dHJpYnV0ZXMgd2hpY2ggZGVwZW5kcyBvbiB0aGUgdHlwZSBvZiB2YXJpYWJsZXMgY29uc2lkZXJlZCBmb3IgZ2VuZXJhdGluZyBhIG1vZGVsLiBUaGlzIGlzIGltcG9ydGFudCBhcyB0aGUgZmFjdG9ycyBtaWdodCBhZmZlY3QgdGhlIHByZWRpY3Rpb24gb2Ygc2FsYXJ5IHNpZ25pZmljYW50bHkuIA0KDQpUaGUgY29lZmZpY2llbnRzIGluIHRoZSBlcXVhdGlvbiBoYXZlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlYWNoIGluZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBkZXBlbmRlbnQgdmFyaWFibGUuIFdoaWxlIHRoaXMgaXMgdHJ1ZSwgYWxzbyBlbnRlcmluZyB2YWx1ZXMgZm9yIGluZGVwZW5kZW50IHZhcmlhYmxlcyBpbnRvIHRoZSBlcXVhdGlvbiBmb3IgcHJlZGljdGluZyBtZWFuIHZhbHVlIGlzIGFjaGlldmFibGUgZm9yIGRlcGVuZGVudCB2YXJpYWJsZS4NCg0KVGhpcyBpcyBuZWVkZWQgZm9yIGdlbmVyYXRpbmcgdW5iaWFzZWQgcHJlZGljdGlvbnMuIA0KR2V0dGluZyBwcmVkaWN0aW9ucyBwcmVjaXNlIGlzIGRvbmUgd2hlbiB0aGUgb2JzZXJ2ZWQgdmFsdWVzIGNsdXN0ZXIgYXJlIGNsb3NlIHRvIHRoZSBwcmVkaWN0ZWQgdmFsdWVzLiBGb3Igc29sdmluZyB0aGlzIGlzc3VlIHdlIGNhbiBjb25zaWRlciBoeXBvdGhlc2lzIA0KDQpOQkEgZGF0YXNldCBpcyBhIGdvb2QgZXhhbXBsZSBmb3Igc29sdmluZyB0aGUgdGFzayBvbiBwcmVkaWN0aW9uIGFzIGl0IHByb3ZpZGVzIHJlbGV2YW50IHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgbGlrZSBBZ2UsIFBFUiwgRlBHLCBHLCBUUywgQVNUIGFuZCBhbHNvIHNvbWUgcXVhbGl0YXRpdmUgdmFyaWFibGVzIGxpa2UgUG9zLCBUbSBldGMuDQoNClRoZSBkYXRhc2V0IHdpbGwgYmUgc3RhdGlzdGljYWxseSBjaGVja2VkIHRvIGRldGVybWluZSBpZiBhc3N1bXB0aW9ucyBhcmUgbWV0IHRvIGRldGVybWluZSBpZiBQb2ludHMgU2NvcmVkKFBQRykgaXMgYSBmYWN0b3IgdGhhdCBhZmZlY3RzIHRoZSBwcmVkaWN0aW9uIHNpZ25pZmljYW50bHkgaS5lIHN0dWR5IHdpbGwgYmUgbmVlZGVkIHRvIHRlc3Qgd2hldGhlciB0aGUgbWVhbiAoUFBHKSBkaWZmZXJzIGFuZCBpcyBhIGZhY3RvciB0aGF0IGlzIGFmZmVjdGluZyB0aGUgc2FsYXJ5IHNpZ25pZmljYW50bHkuIA0KDQpBbGwgc3RhdGlzdGljYWwgYW5hbHlzZXMgd2lsbCBiZSBwZXJmb3JtZWQgdXNpbmcgUiAoc29mdHdhcmUgdmVyc2lvbiA0LjEuMikuDQoNCiMjIyBIeXBvdGhlc2VzDQoqKk51bGwgSHlwb3RoZXNpcyAoSDApOioqTWVhbiBQUEcgaGFzIG5vIGltcGFjdCBvbiBzYWxhcnkgDQokJCBIXzA6IFxtdV8xID0gXG11XzEgPSBcbXVfMyAkJA0KKipBbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIChIYSk6KiogQXRsZWFzdCBzb21lIGRpZmZlcmVuY2UgaW4gTWVhbiBQUEcgaW1wYWN0IHNhbGFyeQ0KJCQgSF9BOiBTb21lfiBcbXV+IGlzIFxuZSAgJCQNCg0KIyMgRGVzaWduL01ldGhvZHMgey50YWJzZXR9DQoNCiogX19UaGUgYXBwcm9hY2ggZm9yIGRlc2lnbmluZyBvdXIgbW9kZWwgd2lsbCBiZSBiYXNlZCBvbiBvdXIgZGF0YXNldCBhbmQgdGhlIHZhcmlhYmxlcyB0aGF0IHdlIGNob29zZS5fXyANCg0KKiBfX1RoZSBvYmplY3RpdmUgb2Ygb3VyIHN0dWR5IGlzIHRvIGJ1aWxkIGEgcmVncmVzc2lvbiBtb2RlbCBhbmQgZXZhbHVhdGUgaXQgYmFzZWQgb24gb3VyIE5CQSBkYXRhc2V0IHZhcmlhYmxlcyBhbmQgcGxheWVyJ3Mgc2Vhc29uX3N0YXRzIGRhdGFzZXQuX18NCg0KKiBfX0Rlc2lnbmluZyB0aGUgbWV0aG9kIGZvciBwcmVkaWN0aW9uIGFuYWx5c2lzIHJlcXVpcmVzIHNlbGVjdGlvbiBvZiB2YXJpYWJsZXMgYmFzZWQgb24gdGhlaXIgY29ycmVsYXRpb24gc3RyZW5ndGggd2l0aCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLl9fIA0KDQojIyMgUmVxdWlyZWQgcGFja2FnZXMNCg0KKiBfX0ZvbGxvd2luZyBhcmUgdGhlIHBhY2thZ2VzIHJlcXVpcmVkIHdpdGggdGhlaXIgdXNlOl9fDQoNCiAgKiBfX3RpZHl2ZXJzZV9fID0gQWxsb3dzIGZvciBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgd29ya3MgaW4gaGFybW9ueSB3aXRoIG90aGVyIHBhY2thZ2VzIGFzIHdlbGwNCg0KICAqIF9fcGxvdGx5X18gPSBncmFwaGljYWwgcmVwcmVzZW50YXRpb24gaW4gcg0KDQogICogX19yc3RhdGl4X18gPSBwZXJmb3JtaW5nIHN0YXRpc3RpY2FsIHRlc3RzDQoNCiAgKiBfX2RhdGEudGFibGVfXyA9IERhdGFmcmFtZSBFbmhhbmNlbWVudCBUb29sDQoNCiAgKiBfX2NvcnJwbG90X18gPSBHZW5lcmF0aW9uIG9mIENvcnJlbGF0aW9uIHBsb3RzDQoNCiAgKiBfX1BlcmZvcm1hbmNlQW5hbHl0aWNzX18gPSBQZXJmb3JtYW5jZSBhbmQgUHJlZGljdGlvbiBBbmFseXRpY3MgUGFja2FnZQ0KDQogICogX19HR2FsbHlfXyA9IEEgZ2dwbG90MiBleHRlbnNpb24NCg0KaW5zdGFsbC5wYWNrYWdlcygicnNjb25uZWN0IikNCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KI0xPQURJTkcgUEFDS0FHRVMNCmxpYnJhcnkoZGF0YS50YWJsZSkgI0VuaGFuY2VkIGRhdGFmcmFtZQ0KbGlicmFyeShjb3JycGxvdCkgICAjRm9yIHBsb3R0aW5nIGNvcnJlbGF0aW9uIHBsb3QNCmxpYnJhcnkoR0dhbGx5KSAgICAgI0FsdGVybmF0aXZlIFBhY2thZ2UoQW4gRXh0ZW5zaW9uKSBmb3IgZ2dwbG90Mg0KbGlicmFyeSh0aWR5dmVyc2UpICAjUGFja2FnZSB0aGF0IHdlIGNhbiB1c2UgZm9yIGRhdGEgYW5hbHlzaXMNCmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpICMgUGFja2FnZSBmb3IgUGVyZm9ybWFuY2UsIFByZWRpY3Rpb24gQW5hbHlzaXMNCmxpYnJhcnkocGxvdGx5KSAjRm9yIGltcHJvdmluZyBHcmFwaGljcyBvbiBwbG90cw0KbGlicmFyeShyc3RhdGl4KSAjUGFja2FnZSBmb3IgcGVyZm9ybWluZyBzdGF0aXN0aWNhbCB0ZXN0cw0KYGBgDQoNCiMjIyBEYXRhIFByZXBhcmF0aW9uDQoNCl9fUGxvdHRpbmcgRmlyc3QgRGF0YVNldF9fDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIERhdGFzZXQgaXMgcmVhZA0KIyNGaXJzdCBkYXRhc2V0DQpzZWFzb25fc2FsYXJ5IDwtIA0KICByZWFkLmNzdigiTkJBX3NlYXNvbjE3MThfc2FsYXJ5LmNzdiIpDQpzZWFzb25fc2FsYXJ5DQoNCmRmIDwtDQogIHJlYWQuY3N2KCJzYWxhcnlfcmVncmVzc2lvbi5jc3YiKQ0KYGBgDQoNCl9fUGxvdHRpbmcgU2Vjb25kIERhdGFzZXRfXw0KDQpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyNTZWNvbmQgZGF0YXNldA0KcGxheWVyX3N0YXRzIDwtIHJlYWQuY3N2KCJTZWFzb25zX1N0YXRzLmNzdiIpDQoNCnBsYXllcl9zdGF0cw0KYGBgDQoNCiMjIyBEYXRhIENvbXBvbmVudCB7LnRhYnNldH0NCg0KKiAqKkNvbHVtbiAiUG9zIjoqKiBQb3NpdGlvbiBhdCB3aGljaCB0aGUgcGxheWVyIGlzIGFzc2lnbmVkIG9yIHBsYXlzIGF0Lg0KKiAqKkNvbHVtbiAiUFRTIjoqKiBQb2ludHMgc2NvcmVkIGJ5IHRoZSBwbGF5ZXINCiogKipDb2x1bW4gIlRtIjoqKiBOYW1lIG9mIFRlYW0gcGxheWVkIGJ5IHRoZSBwbGF5ZXIgZm9yDQoqICoqQ29sdW1uICJHIjoqKiBOby4gb2YgR2FtZXMgcGxheWVkIGJ5IHRoZSBwbGF5ZXINCiogKipDb2x1bW4gIk1QIjoqKiBNaW51dGVzIHBsYXllZCBieSB0aGUgcGxheWVyDQoqICoqQ29sdW1uICJQRVIiOioqIFBlcmZvcm1hbmNlIEVmZmljaWVuY3kgUmF0ZSBmb3IgdGhlIHBsYXllcg0KKiAqKkNvbHVtbiAiQVNUIjoqKiBBc3Npc3RzIG1hZGUgYnkgdGhlIHBsYXllcg0KKiAqKkNvbHVtbiAiVFJCIjoqKiBUb3RhbCBSZWJvdW5kcyBieSB0aGUgUGxheWVyDQoqICoqQ29sdW1uICJUT1YiOioqIFR1cm5vdmVycyBtYWRlIGJ5IHRoZSBwbGF5ZXINCiogKipDb2x1bW4gIkJMSyI6KiogQmxvY2sgbWFkZSBieSB0aGUgcGxheWVyDQoqICoqQ29sdW1uICJTVEwiOioqIFN0ZWFscyBtYWRlIGJ5IHRoZSBwbGF5ZXINCg0KX19BZGRlZCBDb2x1bW5zX18NCg0KKiAqKkNvbHVtbiAiUFBHIjoqKiBQb2ludHMgc2NvcmVkIGJ5IHRoZSBwbGF5ZXIgcGVyIEdhbWUNCiogKipDb2x1bW4gIk1QRyI6KiogTWludXRlcyBwbGF5ZWQgYnkgdGhlIHBsYXllciBwZXIgR2FtZQ0KKiAqKkNvbHVtbiAiQVBHIjoqKiBBc3Npc3RzIG1hZGUgYnkgdGhlIHBsYXllciBwZXIgR2FtZQ0KKiAqKkNvbHVtbiAiUlBHIjoqKiBSZWJvdW5kcyBQZXJjZW50YWdlIHBlciBHYW1lDQoqICoqQ29sdW1uICJUT1BHIjoqKiBUdXJub3ZlciBQZXJjZW50YWdlIHBlciBHYW1lDQoqICoqQ29sdW1uICJCUEciOioqIEJsb2NrIFBlcmNlbnRhZ2UgcGVyIEdhbWUNCiogKipDb2x1bW4gIlNQRyI6KiogU3RlYWwgUGVyY2VudGFnZSBwZXIgR2FtZQ0KDQpfX09idGFpbmluZyB0aGUgdHlwZXMgb2YgRGF0YSBhdmFpbGFibGUgaW4gc2Vhc29uX3NhbGFyeSBkYXRhc2V0X18uDQoNClRoaXMgZGF0YXNldCBjb250YWlucyA1NzMgcm93cyBmb3IgY29sdW1ucyBvZiBYKHBsYXllcl9pZCksIFBsYXllcihOYW1lKSwgVGVhbShUbSkgYW5kIFNlYXNvbiBTYWxhcnkoU2Vhc29uMTdfMTgpLg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KI2Rpc3BsYXlpbmcgZGF0YXR5cGVzIG9mIHZhcmlhYmxlcw0KI2RhdGF0eXBlcyBmb3IgZGF0YXNldCAxDQpzdHIoc2Vhc29uX3NhbGFyeSkNCmBgYA0KDQpfX09idGFpbmluZyB0aGUgdHlwZXMgb2YgRGF0YSBhdmFpbGFibGUgaW4gcGxheWVyX3N0YXRzIGRhdGFzZXRfXy4NCg0KVGhpcyBkYXRhc2V0IGNvbnRhaW5zIDI0NjkxIHJvd3MgZm9yIDUzIGNvbHVtbnMgd2l0aCBtYWpvciBmZWF0dXJlcyBiZWluZywgUG9zaXRpb24oUG9zKSwgQWdlLCBHYW1lcyBQbGF5ZWQoRyksIFBvaW50cyBTY29yZWQoUHRzKSwgTWludXRlcyBQbGF5ZWQoTVApIGV0Yy4NCg0KYGBge3IgZWNobz1GQUxTRX0NCiNkYXRhdHlwZXMgZm9yIGRhdGFzZXQgMg0Kc3RyKHBsYXllcl9zdGF0cykNCmBgYA0KDQojIyMgRGF0YSBDbGVhbmluZw0KDQpfX1RoZSBmaWx0ZXJhdGlvbiB0ZWNobmlxdWUgd2FzIHVzZWQgdG8gb2J0YWluIGEgZGF0YXNldCBmb3IgcGxheWVyJ3Mgc3RhdHMgYmFzZWQgb24gdGhlIHllYXI6IDIwMTZfXw0KDQpfX1RoZXJlIHdhcyBhIG5lZWQgdG8gbXV0YXRlIGZlYXR1cmVzIGxpa2UgTVBHLCBQUEcsIEFQRyBldGMuIHRvIHBlcmZvcm0gcmVncmVzc2lvbiBhbmFseXNpcyBiYXNlZCBvbiBwZXIgR2FtZS5fXw0KDQpfX0ZpbHRlcmVkIGRhdGEgY2FuIGJlIHZpZXdlZCBoZXJlIGFzOl9fDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCiNGaWx0ZXJpbmcgZGF0YXNldCBmb3IgcmVjZXZpbmcgZGF0YXBvaW50cyBmb3IgdGhlIHllYXI6IDIwMTYuDQojU2VsZWN0aW5nIHJlbGV2YW50IHZhcmlhYmxlcyBsaWtlIFllYXIsIEcsIFBFUiwgRkcsIFBUUyBldGMuDQojTXV0YXRpbmcgY29sdW1ucyBuYW1lZCBNUEcsIFJQRywgUFBHLCBBUEcsIFRPUEcsIEJQRywgU1BHIGZvciBmdXJ0aGVyIGFuYWx5c2lzDQpmaWx0ZXJlZF8yMDE2IDwtIA0KICBwbGF5ZXJfc3RhdHMgJT4lIGZpbHRlcihZZWFyID09IDIwMTYpICU+JSANCiAgc2VsZWN0KFllYXI6RywgTVAsIFBFUiwgRkc6UFRTKSAlPiUgDQogIGRpc3RpbmN0KFBsYXllciwgLmtlZXBfYWxsID0gVFJVRSkgJT4lIA0KICBtdXRhdGUoTVBHID0gTVAvRywgUFBHID0gUFRTL0csIEFQRyA9IEFTVC9HLCANCiAgICAgICAgIFJQRyA9IFRSQi9HLCBUT1BHID0gVE9WL0csIEJQRyA9IEJMSy9HLCANCiAgICAgICAgU1BHID0gU1RML0cpDQpmaWx0ZXJlZF8yMDE2DQpgYGANCg0KIyMjIE1lcmdpbmcgRGF0YQ0KDQpfX091ciBtZXJnZWQgZGF0YSBiZXR3ZW4gZmlsdGVyZWRfMjAxNiBkYXRhc2V0IGFuZCBzZWFzb25fc2FsYXJ5IGRhdGFzZXQgY2FuIGJlIHZpZXdlZCBoZXJlLl9fDQoNCmBgYHtyIGVjaG89RkFMU0V9DQojIFBlcmZvcm1pbmcgZnVsbCBqb2luIHVzaW5nIG1lcmdlIGZ1bmN0aW9uIGZvciBKb2luaW5nIGZpbHRlcmVkXzIwMTYgZGF0YXNldCBhbmQgc2Vhc29uX3NhbGFyeSBkYXRhc2V0IGJhc2VkIG9uIGNvbW1vbiB2YXJpYWJsZSAiUGxheWVyIi4NCnNhbGFyeV9uZXcgPC0gbWVyZ2UoZmlsdGVyZWRfMjAxNiwgc2Vhc29uX3NhbGFyeSwgYnkueCA9ICJQbGF5ZXIiLCBieS55ID0gIlBsYXllciIpDQojIFJlbmFtaW5nIGEgY29sdW1uIGZvciBzYWxhcnkNCm5hbWVzKHNhbGFyeV9uZXcpWzQwXSA8LSAiZmlsdGVyX3NhbCINCiNEZWxldGluZyB1bndhbnRlZCBjb2x1bW4NCnNhbGFyeV9uZXcgPC0gc2FsYXJ5X25ld1stMzldDQoNCnNhbGFyeV9uZXcNCmBgYA0KDQoNCiMjIyBDb3JyZWxhdGlvbiBjaGVjayB7LnRhYnNldH0NCg0KIyMjIyBDb3JyZWxhdGlvbiBjaGVjayBObzENCg0KX19Gb2xsb3dpbmcgcGxvdCBpcyBmb3IgY2hlY2tpbmcgY29ycmVsYXRpb25fXw0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KI0dlbmVyYXRpbmcgY29ycmVsYXRpb24gcGxvdCBmb3Igc2FsYXJ5IHdpdGggb3RoZXIgaW5mbHVlbnRpYWwgdmFyaWFibGVzDQojdG8gY2hlY2sgd2hldGhlciB0aGVzZSB2YXJpYWJsZXMgaGF2ZSBjb3JyZWxhdGlvbi4NCmNvcnJwbG90KGNvcihzYWxhcnlfbmV3ICU+JSANCiAgICAgICAgICAgICAgIHNlbGVjdChmaWx0ZXJfc2FsLCBNUEc6U1BHLCANCiAgICAgICAgICAgICAgICAgICAgICBBZ2UsIFBFUiwgY29udGFpbnMoIiUiKSksIA0KICAgICAgICAgICAgIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwgDQogICAgICAgICBtZXRob2QgPSAibnVtYmVyIix0eXBlID0gInVwcGVyIikNCmBgYA0KDQoNCiMjIyMgQ29ycmVsYXRpb24gY2hlY2sgTm8yDQoNCl9fRm9sbG93aW5nIHBsb3QgaXMgZm9yIGNoZWNraW5nIGNvcnJlbGF0aW9uX18NCg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KIyMgUGxvdHRpbmcgc2NhdHRlcnBsb3QgbWF0cml4IGZvciBjb3JyZWxhdGlvbiBmb3IgZmVhdHVyZXMgd2l0aCBzYWxhcnkgdmFyaWFibGVzLg0KIyBNYWRlIHVzZSBvZiBnZ3BhaXJzIGZ1bmN0aW9uLg0KY29yX3NhbGFyeV9uZXcgPC0gDQogIHNhbGFyeV9uZXcgJT4lIA0KICBzZWxlY3QoZmlsdGVyX3NhbCwgUFBHLCBNUEcsIFRPUEcsIFJQRywgUEVSLCBTUEcsIEFQRykNCmdncGFpcnMoY29yX3NhbGFyeV9uZXcpDQpgYGANCg0KDQojIyMjIENvcnJlbGF0aW9uIEFuYWx5c2lzDQoNCl9fVGFibGUgc2hvd3MgdGhlIGNvcnJlbGF0aW9uIHZhbHVlIGZvciB0aGUgZm9sbG93aW5nIHZhcmlhYmxlc19fDQoNCmBgYHtyIGVjaG89RkFMU0V9DQojQ29ycmVsYXRpb24gdGFibGUNCmNvcihjb3Jfc2FsYXJ5X25ldylbLCJmaWx0ZXJfc2FsIl0NCmBgYA0KDQpDb3JyZWxhdGlvbiBzdHJlbmd0aCBpczoNClBQRyA+IE1QRyA+IFRPUEcgPiBSUEcgPiBQRVIgPiBTUEcgPiBBUEcNCg0KVGhlIGludGVyZXN0aW5nIHBhcnQgb2YgdGhpcyBpcyB0aGF0IHRoZSBudW1iZXIgb2YgdHVybm92ZXJzIHBsYXllcnMgbWFrZSBpbiBkaXJlY3QgY29ycmVsYXRpb24gdG8gdGhlaXIgc2FsYXJ5LCBhbmQgdGhlIHJlbGF0aW9uc2hpcCBzaG93cyBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uLg0KDQpUaGUgaW50ZXJwcmV0YXRpb24gY2FuIGJlIGRlbW9uc3RyYXRlZCBpbiB0aGUgZm9sbG93aW5nIHdheToNCg0KVGhlIG1vcmUgdHVybm92ZXJzIHRoZXkgbWFrZSB3aWxsIHJlc3VsdCBpbiBpbmNyZWFzZWQgaW52b2x2ZW1lbnQgYW5kIG91dGNvbWUgd2lsbCBiZSBtb3JlIGJhbGwgbW92ZW1lbnRzIGluIGEgZ2FtZS4NCg0KVGhpcyB3YXksIHdlIGNhbiBjbGFpbSB0aGF0IHRoZSBwbGF5ZXJzIHdobyBtYWtlIG1vcmUgdHVybm92ZXJzLCBhcmUgZGlyZWN0bHkgb3IgYXQgaW1wb3J0YW50IHRvIHRoZWlyIHRlYW0uIFRoaXMgY2FuIGJlIGV4cHJlc3NlZCBhcyAiYWdyZXNzaXZlbmVzcyIuIA0KDQpUaGlzIGFzc3VtcHRpb24gd2lsbCBiZSB1c2VkIGluIHBsYWNlIG9mIHRoZSBkdXJhdGlvbiBmb3Igd2hpY2ggcGxheWVyIGhvbGRzL2NvbnRhaW5zIGJhbGwgaW4gcG9zc2Vzc2lvbiBpbiBhIGdhbWUuDQoNCiMjIyBEYXRhIFZpc3VhbGl6YXRpb24gey50YWJzZXR9DQoNCiMjIyMgRGF0YVNldCBwbG90dGluZw0KDQpGb2xsb3dpbmcgcGxvdCBzaG93cyB0aGUgQm94cGxvdCBkaXN0cmlidXRpb24gb2YgUG9pbnRzIHNjb3JlZCBwZXIgZ2FtZS4gV2UgY2FuIHNlZSBtdWx0aXBsZSBvdXRsaWVycyBpbiB0aGlzIGdyYXBoLiBUaGlzIGdyYXBoIGRpc3BsYXkgbWVkaWFuIHZhbHVlIGFzIDguIEFuZCwgdGhlIG91dGxpZXJzIGFyZSBhY2N1bXVsYXRlZCBuZWFyIHRoZSByYW5nZSAyNS0zMC4NCg0KYGBge3IgZWNobz1GQUxTRX0NCmdncGxvdChkZiwNCiAgICAgICBhZXMoeD1QUEcpKSArDQogIGdlb21fYm94cGxvdChmaWxsPSJibHVlIiwNCiAgICAgICAgICAgICAgIG91dGxpZXIuY29sb3IgPSAiI0Y1NjYwMCIsIG91dGxpZXIuc2l6ZSA9IDMuMCkNCmBgYA0KDQojIyMjIEludGVyYWN0aXZlIFBsb3QNCg0KYGBge3IgZWNobz0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KI0dlbmVyYXRpb24gb2YgSW50ZXJhY3RpdmUgcGxvdCBmb3IgcGxvdHRpbmcgaW5mbHVlbmNlIG9mIHNhbGFyeSByZWNlaXZlZCBieSB0aGUgcGxheWVyIG92ZXIgcG9pbnRzIHNjb3JlZCBwZXIgZ2FtZS4NCiNwbG90bHkgZnVuY3Rpb24gaXMgdXNlZA0KI2hvdmVyaW5mbyBhcmd1bWVudCBwcm92aWRlcyB1c2VmdWwgdGVjaG5pcXVlIGluIGdlbmVyYXRpbmcgYSBwbG90IHdpdGggZHluYW1pYyBuYXR1cmUuIEV4dHJlbWVseSB1c2VmdWwgZm9yIHBsb3R0aW5nIHJlYWwtdGltZSBkYXRhLg0KbmFtZXMoc2FsYXJ5X25ldylbNV0gPC0gIlRlYW0iDQpwbG90X2x5KGRhdGEgPSBzYWxhcnlfbmV3LCB4ID0gfmZpbHRlcl9zYWwsIHkgPSB+UFBHLCBjb2xvciA9IH5UZWFtLA0KICAgICAgICBob3ZlcmluZm8gPSAidGV4dCIsDQogICAgICAgIHRleHQgPSB+cGFzdGUoIlBsYXllcjogIiwgUGxheWVyLA0KICAgICAgICAgICAgICAgICAgICAgICI8YnI+U2FsYXJ5OiAiLCBmb3JtYXQoZmlsdGVyX3NhbCwgYmlnLm1hcmsgPSAiLCIpLCIkIiwNCiAgICAgICAgICAgICAgICAgICAgICAiPGJyPlBQRzogIiwgcm91bmQoUFBHLCBkaWdpdHMgPSAzKSwNCiAgICAgICAgICAgICAgICAgICAgICAiPGJyPlRlYW06ICIsIFRlYW0pKSAlPiUgDQogIGxheW91dCgNCiAgICB0aXRsZSA9ICJTYWxhcnkgdnMgUG9pbnQgUGVyIEdhbWUiLA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJQbGF5ZXIncyBTYWxhcnkgaW4gVVNEIiksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlBvaW50IHBlciBHYW1lIGZvciBQbGF5ZXIiKQ0KICApDQpgYGANCg0KDQpXaGVuIGhvdmVyZWQgb3ZlciB0aGUgaGlnaGVzdCB2YWx1ZWQgZGF0YSwgd2UgcmVjZWl2ZSB0aGUgZm9sbG93aW5nIGluZm9ybWF0aW9uIGZvciB0aGUgZGF0YSBwb2ludC4NCg0KKiBUaGUgbW9zdCBwYWlkIHBsYXllciB3aXRoICQzNCw2ODIsNTUwIGlzDQogICogU3RlcGhlbiBDdXJyeQ0KICAqIFNjb3JlcyAzMC4wNjMgUFBHDQogICogUGxheXMgZm9yIFRlYW06IEdvbGRlbiBTdGF0ZSBXYXJyaW9ycw0KDQojIyMjIFNpbXBsZSBMaW5lYXIgUmVncmVzc2lvbiBNb2RlbCB7LnRhYnNldH0NCg0KIyMjIyMgU2NhdHRlciBwbG90IHdpdGggcmVncmVzc2lvbiBsaW5lDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojUGxvdHRpbmcgc2NhdHRlcnBsb3Qgb2YgcmVncmVzc2lvbiBNb2RlbCBmb3Igc2FsYXJ5IHZhcmlhYmxlIG9uIFBvaW50cyBTY29yZWQgcGVyIEdhbWUgdG8gc2VlIHZhcmlhbmNlIGluIHRoZSBncmFwaA0Kc2FsYXJ5X25ldyAlPiUgDQogIGdncGxvdChhZXMoeCA9IGZpbHRlcl9zYWwsIHkgPSBQUEcpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKw0KICBsYWJzKHg9ICJTYWxhcnkiLCB5PSJQUEciKQ0KYGBgDQoNCiMjIEFuYWx5c2lzIHsudGFic2V0fQ0KDQojIyMgUmVncmVzc2lvbiBBbmFseXNpcyB7LnRhYnNldH0NCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiNGaXR0aW5nIGEgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgYnkgc2VsZWN0aW5nIGFsbCB2YXJpYWJsZXMgYmV0d2VlbiBNUEcgYW5kIFNQRy4NCnNhbGFyeV9yZWdyZXNzaW9uIDwtIA0KICBzYWxhcnlfbmV3ICU+JSBzZWxlY3QoZmlsdGVyX3NhbCwgTVBHOlNQRykNCmxtKGZpbHRlcl9zYWx+LiwgZGF0YT1zYWxhcnlfcmVncmVzc2lvbikNCmBgYA0KDQoqIF9fU3RhdGlzdGljYWwgSW5zaWdodHNfXw0KICAqIFNhbGFyeSByaXNlcyBieSAkOTk4LDcyNCBwZXIgeWVhciBkdWUgdG8gdGhlIGVmZmVjdCBvZiBQb2ludHMgUGVyIEdhbWUgYnkgUGxheWVyDQogICogTW9yZSBBc3Npc3QgUGVyIEdhbWUgYWxzbyByZXN1bHRzIGluIGluY3JlYXNlIGluIFNhbGFyeSANCg0KIyMjIyBUcnVzdCBGYWN0b3Igb24gUGxheWVyKGJ5IENvYWNoKTogRGVwZW5kcyBvbiBOdW1iZXIgb2YgdHVybm92ZXJzIHRoZXkgbWFrZS4uDQoNCmBgYHtyIGVjaG89RkFMU0V9DQojRm9yIGRldGVybWluaW5nIHRoZSBlZmZlY3Qgb2YgVHJ1c3Qgb24gVHVybm92ZXJzLg0KI09idGFpbmluZyBhdmVyYWdlIGZvciBNUEcgZmVhdHVyZSB1c2luZyBtZWFuIGZ1bmN0aW9uDQphdmcubWludXRlcyA8LSBtZWFuKHNhbGFyeV9yZWdyZXNzaW9uJE1QRykNCiNPYnRhaW5pbmcgYXZlcmFnZSBmb3IgVE9QRyBmZWF0dXJlIHVzaW5nIG1lYW4gZnVuY3Rpb24NCmF2Zy50dXJub3ZlciA8LSBtZWFuKHNhbGFyeV9yZWdyZXNzaW9uJFRPUEcpDQojQ29udmVydGluZyBjYXRlZ29yaWNhbCB2YXJpYWJsZSBpbnRvIGZhY3RvcnMgZm9yIFllcyBhbmQgTm8gdmFsdWVzDQpzYWxhcnlfcmVncmVzc2lvbiRUcnVzdGVkIDwtIGFzLmZhY3RvcihpZmVsc2Uoc2FsYXJ5X3JlZ3Jlc3Npb24kTVBHID49IGF2Zy5taW51dGVzLCAiWWVzIiwgIk5vIikpDQojQ29udmVydGluZyBjYXRlZ29yaWNhbCB2YXJpYWJsZSBpbnRvIGZhY3RvcnMgZm9yIFllcyBhbmQgTm8gdmFsdWVzDQpzYWxhcnlfcmVncmVzc2lvbiRBZ3Jlc3NpdmVuZXNzIDwtIGFzLmZhY3RvcihpZmVsc2Uoc2FsYXJ5X3JlZ3Jlc3Npb24kVE9QRyA+PSBhdmcudHVybm92ZXIsICJZZXMiLCAiTm8iKSkNCiNQcmludGluZyBmaXJzdCAxMCByb3dzIG9mIHRoZSBkYXRhc2V0DQpoZWFkKHNhbGFyeV9yZWdyZXNzaW9uKQ0KYGBgDQoNCg0KIyMjIyBQcmFsbGVsIFNsb3BlIE1vZGVsIHsudGFic2V0fQ0KDQojIyMjIyBTY2F0dGVyIHBsb3QgY29sb3VyZWQgYnkgaG93IG1hbnkgdHVybm92ZXJzIHRoZXkgbWFrZQ0KDQpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyBHZW5lcmF0aW5nIHJlZ3Jlc3Npb24gcGxvdCB0byBkZXRlcm1pbmUgYW55IGRpZmZlcmVuY2UgaW4gc2FsYXJ5IGJhc2VkIG9uIEFncmVzc2l2ZW5lc3MNCnNhbGFyeV9yZWdyZXNzaW9uICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZmlsdGVyX3NhbCwgeSA9IFBQRywgY29sb3VyID0gQWdyZXNzaXZlbmVzcykpICsgDQogIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikNCmBgYA0KDQpfX1RoaXMgcHJvdmVzIHRoZSBBc3N1bXB0aW9uIHRoYXQgdGhlIHBsYXllciB3aG8gbWFrZXMgbW9yZSBudW1iZXIgb2YgdHVybm92ZXJzIHdpbGwgZ2V0IHBhaWQgaGlnaGVyIG9yIHdpbGwgcmVjZWl2ZSBpbmNyZWFzZSBpbiBTYWxhcnkuX18gDQoNCiMjIyBNb2RlbGluZyAmIE1vZGVsX2ZpdCBSZXN1bHRzIHsudGFic2V0fQ0KDQpfX0ZpbmRpbmcgU2FsYXJ5IGZvciBhbiBhdmVyYWdlIHBsYXllciBpcyBuZWNlc3NhcnkgZm9yIGRldGVybWluaW5nIHRoZSBwZXIgc2FsYXJ5IGluY3JlYXNlIGFmdGVyIHRha2luZyBUcnVzdGVkIGFuZCBBZ3Jlc3NpdmVuZXNzIGZhY3RvcnMgaW50byBjb25zaWRlcmF0aW9uLl9fDQoNCl9fQW4gYXZlcmFnZSBwbGF5ZXIgcmVjZWl2ZXMgdGhlIGZvbGxvd2luZyBTYWxhcnkgcGVyIFNlYXNvbl9fDQoNCmBgYHtyIGVjaG89RkFMU0V9DQojR2V0dGluZyBhdmVyYWdlIHBsYXllcidzIHNhbGFyeSBieSBmaW5kaW5nIHRoZSBtZWFuIGZvciBhbGwgcGxheWVycw0KbWVhbl9zYWxhcnkgPC0gbWVhbihzYWxhcnlfcmVncmVzc2lvbiRmaWx0ZXJfc2FsKQ0KbWVhbl9zYWxhcnkNCmBgYA0KDQpfX0hlcmUgd2UgYXJlIGdlbmVyYXRpbmcgYSBNdWx0aXBsZSBSZWdyZXNzaW9uIG1vZGVsIGJhc2VkIG9uIEZhY3RvcnMgbGlrZSBUcnVzdGVkIGFuZCBBZ3Jlc3NpdmVuZXNzX18uDQoNCl9fV2UgY2FuIGRldGVybWluZSB0aGUgbW9kZWxfZml0IGJ5IG9idGFpbmluZyB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBmZWF0dXJlc19fOg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KI0ZpdHRpbmcgYSBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsIGZvciBzYWxhcnkgYmFzZWQgb24gVHJ1c3RlZCBhbmQgQWdyZXNzaXZlbmVzcw0KdHJ1c3RfbG0gPC0gbG0oZm9ybXVsYSA9IGZpbHRlcl9zYWwgfiBUcnVzdGVkICogQWdyZXNzaXZlbmVzcywgZGF0YT1zYWxhcnlfcmVncmVzc2lvbikNCiNQbG90dGluZyBzdW1tYXJ5IHRhYmxlIGZvciBvdXIgcmVncmVzc2lvbiBtb2RlbA0Kc3VtbWFyeSh0cnVzdF9sbSkNCmBgYA0KDQpfX09idGFpbmluZyBDb2VmZmljaWVudHMgZm9yIHRoZSBmZWF0dXJlc19fLg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KIyBDb2VmZmljaWVudHMgVGFibGUNCmNvZWYodHJ1c3RfbG0pDQpgYGANCg0KKiBfX1Jlc3VsdHNfXw0KDQogICogVGhlcmUgaXMgYSBkaXJlY3QgY29ycmVsYXRpb24gYmFzZWQgb24gdHJ1c3QgYW5kIHNhbGFyeSBpbmNyZWFzZS4NCg0KICAqIFRoaXMgbGVhZHMgdG8gbW9yZSBwbGF5IHRpbWUgYWxsb3dlZCBieSBjb2FjaCBhbmQgaW5jcmVhc2UgaW4gcHJvYmFiaWxpdHkgdG8gc2NvcmUgbW9yZSBQb2ludHMgcGVyIEdhbWUoUFBHKS4NCg0KICAqIFRoZSBzYWxhcnkgd2lsbCBpbmNyZWFzZSBieSBfXyQzMTEsNDE2X18uDQoNCg0KIyMjIEFuYWx5c2lzICYgY29uY2x1c2lvbg0KDQojIyMjIFByZWRpY3Rpb24gRnVuY3Rpb24NCg0KTGV0J3MgdHJ5IHRvIHByZWRpY3Qgc2FsYXJ5IGZvciB0aGUgTW9zdCBWYWx1YWJsZSBQbGF5ZXIgZm9yIHRoZSB5ZWFyIDIwMTYuIFRoZSBQcm9mZXNzaW9uYWwgQmFza2V0YmFsbGVyICJSdXNzZWwgV2VzdGJyb29rIiBwbGF5ZWQgZm9yIHRoZSB0ZWFtIE9rbGFob21hIENpdHkgVGh1bmRlciBhbmQgaGFzIGEgc2Vuc2F0aW9uYWwgc2Vhc29uIGJvdGggaW4gUmVndWxhciBhbmQgUGxheW9mZnMgU2Vhc29uIGFzIHdlbGwuDQoNCjxjZW50ZXI+DQohW1JCXShSdXNzZWxfcGljLnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQoNClRoZSBzdGF0aXN0aWNzIGZvciBoaXMgcGVyZm9ybWFuY2Ugd2FzIHJlZmVyZW5jZWQgYnkgdGhlIHdlYnNpdGUgW0Jhc2tldGJhbGwgUmVmZXJlbmNlOiBSdXNzZWwgV2VzdGJyb29rXShodHRwczovL3d3dy5iYXNrZXRiYWxsLXJlZmVyZW5jZS5jb20vcGxheWVycy93L3dlc3RicnUwMS9nYW1lbG9nLzIwMTcpLg0KDQpSdXNzZWwgV2VzdGJyb29rJ3MgU3RhdGlzdGljcyBmb3IgdGhlIHllYXIgd2FzOg0KDQoqIF9fUG9pbnRzIHBlciBHYW1lIChQUEcpOiAzMS42X18NCg0KKiBfX01pbnV0ZXMgcGxheWVkIHBlciBHYW1lIChNUEcpOiAzNC42X18NCg0KKiBfX1R1cm5vdmVycyBwZXIgR2FtZSAoVE9QRyk6IDUuNF9fDQoNCg0KDQojIyMjIENvbmNsdXNpb24NCg0KYGBge3IgZWNobz1GQUxTRX0NCiNCdWlsZGluZyBhIHByZWRpY3Rpb24gZnVuY3Rpb24gZm9yIHByZWRpY3RpbmcgdmFsdWUgYmFzZWQgb24gUFBHLCBNUEcsIFRPUEcuDQojIFByaW50aW5nIG91dHB1dCB2YWx1ZSBmb3Igb3VyIGZ1bmN0aW9uDQpzYWxhcnlfcHJlZGljdGlvbiA8LSBmdW5jdGlvbihtLCBwb2ludCwgbWludXRlcywgdHVybl9vdmVyKXsNCiAgcHJlX25ldyA8LSBwcmVkaWN0KG0sIGRhdGEuZnJhbWUoUFBHID0gcG9pbnQsIE1QRyA9IG1pbnV0ZXMsIFRPUEcgPSB0dXJuX292ZXIpKQ0KICBtc2cgPC0gcGFzdGUoIlBQRzoiLCBwb2ludCwgIixNUEc6IiwgbWludXRlcywgIixUT1BHOiIsIHR1cm5fb3ZlciwgIiA9PT4gRXhwZWN0ZWQgU2FsYXJ5IGZvciBwbGF5ZXI6ICQiLCBmb3JtYXQocm91bmQocHJlX25ldyksIGJpZy5tYXJrID0gIiwiKSwgc2VwID0gIiIpDQogIHByaW50KG1zZykNCn0NCmBgYA0KDQpfX0Jhc2VkIG9uIHRoZSBzdGF0cyBmb3IgUnVzc2VsIFdlc3Ricm9vaywgd2UgZ2VuZXJhdGUgYSBwcmVkaWN0aW9uX2ZpdCBtb2RlbCBhbmQgY29tcHV0ZSB0aGUgUHJlZGljdGlvbiBTYWxhcnlfXy4NCg0KYGBge3IgZWNobz1GQUxTRX0NCiMgRml0dGluZyB2YWx1ZXMgZm9yIG9idGFpbmluZyBvdXRwdXQNCm1vZGVsIDwtIGxtKGZvcm11bGEgPSBmaWx0ZXJfc2FsIH4gUFBHICsgTVBHICsgVE9QRywgZGF0YSA9IHNhbGFyeV9yZWdyZXNzaW9uKQ0Kc2FsYXJ5X3ByZWRpY3Rpb24obW9kZWwsIDMxLjYsIDM0LjYsIDUuNCkNCmBgYA0KDQoqIF9fQWNjb3JkaW5nIHRvIG15IHByZWRpY3Rpb24gbW9kZWwsIGhlIHdpbGwgZ2V0ICQyNSw3MDcsMzYzIG5leHQgc2Vhc29uLl9fDQoNCiogX19UaGUgT2ZmaWNpYWwgU2FsYXJ5IFJ1c3NlbCBXZXN0YnJvb2sgcmVjZWl2ZWQgaW4gaGlzIG5leHQgc2Vhc29uIHdhczogJDI4LDUzMCw2MDguX18NCg0KKiBUaGlzIHJlc3VsdGVkIHdpdGggYSA5MyBwZXJjZW50IGFjY3VyYWN5IGZvciBvdXIgcHJlZGljdGlvbiBtb2RlbC4NCg0KDQojIyBTdW1tYXJ5DQoNCk91ciBBc3Nlc3NtZW50IFN0dWR5IG9mIHRoaXMgRGF0YXNldCBwcm92aWRlZCBtYW55IGRlZXAgaW5zaWdodHMgYWJvdXQgdGhlIGRhdGFzZXQuIA0KQmFzZWQgb24gb3VyIHN0dWR5Og0KDQoqIF9fV2Ugd2VyZSBhYmxlIHRvIGNsZWFuIHRoZSBkYXRhIGFuZCByZW1vdmUgbnVsbCB2YWx1ZXMgb3IgaXJyZWxldmFudCB2YXJpYWJsZXMgZnJvbSB0aGUgZGF0YV9fLg0KKiBfX1dlIHdlcmUgYWJsZSB0byBNdXRhdGUgY29sdW1ucyBmb3IgdHdvIGRhdGFzZXRzIHdoaWNoIHByb3ZpZGVkIHVzIHdpdGggYSBiZXR0ZXIgZGF0YXNldCB0byBwdXJzdWUgb3VyIHN0dWR5IG9uX18uDQoqIF9fV2Ugd2VyZSBhYmxlIHRvIGNoZWNrIGRpZmZlcmVudCB0eXBlcyBvZiBkYXRhdHlwZXMgcHJlc2VudCBpbiBvdXIgZGF0YXNldF9fLg0KKiBfX1dlIGZpZ3VyZWQgb3V0IGhvdyBtYW55IHZhcmlhYmxlcyBhcmUgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyBhbmQgaG93IG1hbnkgdmFyaWFibGVzIGFyZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXNfXy4gDQoqIF9fQmFzZWQgb24gcXVhbnRpdGF0aXZlIHZhcmlhYmxlcywgd2Ugd2VyZSBhYmxlIHRvIHBlcmZvcm0gRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyB1c2luZyBoaXN0b2dyYW0gcGxvdCwgc2NhdHRlcnBsb3QgIGFuZCBvYnRhaW4gZGVlcGVyIGluc2lnaHRzIG9mIG91ciBkYXRhX18uIA0KKiBfX0Jhc2VkIG9uIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3ZSB3ZXJlIGFibGUgdG8gc3BsaXQgb3VyIGRhdGFzZXRzIG9uIGxldmVscyB1c2luZyBmYWN0b3JzIHZhcmlhYmxlcyBpbiB2YXJpYWJsZXMgbGlrZSBBZ2dyZXNzaXZlbmVzcywgYW5kIFRydXN0ZWQgZXRjX18uDQoqIF9fV2Ugd2VyZSBhYmxlIHRvICBkZXRlcm1pbmUgaW5mbHVlbnRpYWwgdmFyaWFibGVzIGluIG91ciBkYXRhX18uDQoqIF9fV2Ugd2VyZSBhYmxlIHRvIGRldGVybWluZSBhIHRyZW5kIG9uIGhvdyBoaWdoZXIgcGxheWVkIHBsYXllcnMocGxheWVycyB3aXRoIGhpZ2hlciBzYWxhcmllcykgdGVuZCB0byBzY29yZSBtb3JlIHBvaW50cyBwZXIgR2FtZV9fLg0KKiBfX1dlIHdlcmUgYWJsZSB0byBkZXRlcm1pbmUgY29ycmVsYXRpb24gYmV0d2VlbiB2YXJpYWJsZXMgYW5kIGhvdyB0aGV5IGltcGFjdCB0aGUgcGxheWVyJ3Mgc2FsYXJ5X18uDQoqIF9fVGhyb3VnaCBIeXBvdGhlc2lzIFRlc3RpbmcsIFdlIHdlcmUgYWJsZSB0byBwcm92ZSBob3cgaGlnaGVzdCBjb3JyZWxhdGVkIHZhcmlhYmxlIFBQRyBoYXMgYSBzaWduaWZpY2FudCBpbXBhY3Qgb24gcGxheWVyJ3MgU2FsYXJ5IGFuZCBsZWFkcyB0byBpbmNyZWFzZSBpbiBzYWxhcnlfXy4NCiogX19UaHJvdWdoIG1vZGVsIGZpdHRpbmcsIHdlIHN1Y2Nlc3NmdWxseSBhY2hpZXZlZCB0aGUgdGFzayBvZiBnZW5lcmF0aW5nIHByZWRpY3Rpb24gYmFzZWQgb24gaGlnaGx5IGluZmx1ZW50aWFsIHZhcmlhYmxlc19fLiAgDQoqIF9fV2Ugd2VyZSBhYmxlIHRvIGFjaGlldmUgYW4gb3V0c3RhbmRpbmcgYWNjdXJhY3kgcmF0ZSBvZiA5MyBwZXJjZW50IHVzaW5nIHRoaXMgbW9kZWxfXy4NCiogX19XZSBhbHNvIHdlcmUgYWJsZSB0byBhbnN3ZXIgdGhlIGFzc3VtcHRpb25zIG9mIGhvdyBhIENvYWNoJ3MgdHJ1c3QgZmFjdG9yIGZvciBhIHBsYXllciBpbmNyZWFzZXMgUG9pbnRzIHNjb3JlZCBwZXIgR2FtZSBieSBhIHBsYXllciBhbmQgaXMgYWJsZSB0byBnZW5lcmF0ZSBtb3JlIHR1cm5vdmVycyBkdXJpbmcgdGhlIGdhbWVfXy4NCiogX19UaGVzZSBhc3N1bXB0aW9ucyBhbHNvIHByb3ZpZGVkIHVzIHdpdGggYSBuZXcgdHJlbmQgb24gZGV0ZXJtaW5pbmcgc2lnbmlmaWNhbnQgaW1wYWN0IChpbmNyZWFzZSkgaW4gcGxheWVyJ3MgU2FsYXJ5X18uDQoqIEZpbmFsbHkgZm9yIGNoZWNraW5nIHRoZSB3b3JraW5nIG9mIG91ciBwcmVkaWN0aW9uIG1vZGVsLCB3ZSBQZXJmb3JtZWQgcHJlZGljdGlvbiBmb3IgdGhlIE1vc3QgVmFsdWFibGUgUGxheWVyIGZvciB0aGUgeWVhciAyMDE2OiBfX1J1c3NlbCBXZXRicm9va19fLg0KDQoNCg0KIyMgUmVmZXJlbmNlcw0KDQpbR2l0aHViLmNvbV0NCihodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9mbGV4ZGFzaGJvYXJkKQ0KDQoNCltSU3R1ZGlvIFdlYnNpdGVdDQooaHR0cHM6Ly9zaGlueS5yc3R1ZGlvLmNvbS9nYWxsZXJ5LykNCg0KW0xBQiBmaWxlcyBhbmQgSG9tZXdvcmsgZmlsZXMtIFNUQVQtNjAyMF0NCihodHRwczovL2NsZW1zb24uYXBwLmJveC5jb20vcy91Znh0cDZ5anY2b3Y4anM1ZzNkam1kN3p3Z3h2ZDZlZCkNCg0KW0thZ2dsZS5jb21dDQooaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9rb2tpMjVhbmRvL3NhbGFyeT9zZWxlY3Q9TkJBX3NlYXNvbjE3MThfc2FsYXJ5LmNzdikNCg0KW0Jhc2tldGJhbGwgUmVmZXJlbmNlOiBSdXNzZWwgV2VzdGJyb29rXQ0KKGh0dHBzOi8vd3d3LmJhc2tldGJhbGwtcmVmZXJlbmNlLmNvbS9wbGF5ZXJzL3cvd2VzdGJydTAxL2dhbWVsb2cvMjAxNykNCg0KW01lZGl1bS5jb21dDQooaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL3ByZWRpY3RpbmctaG91c2luZy1wcmljZXMtd2l0aC1yLWM5ZWMwODIxMzI4ZCkNCg0KW1JwdWJzLmNvbV0NCihodHRwczovL3JwdWJzLmNvbS9pc2hhbnRuYXllci8yMzQyMjEpDQoNCg0KIyMgUGVyc29uYWwgSW5mb3JtYXRpb24NCg0KIyMjIEFtb2doIFNpbmdoDQoNCkkgYW0gYSBHcmFkdWF0ZSBTdHVkZW50IGF0IENsZW1zb24gVW5pdmVyc2l0eSBwZXJ1c2luZyBoaXMgTWFzdGVy4oCZcyBkZWdyZWUgaW4gQ29tcHV0ZXIgU2NpZW5jZS4gSSBoYXZlIGNvbXBsZXRlZCBCYWNoZWxvcidzIGluIENvbXB1dGVyIEVuZ2luZWVyaW5nIGZyb20gTXVtYmFpLCBJbmRpYSBhbmQgaGF2ZSBkZXZlbG9wZWQgZGVlcCBpbnRlcmVzdCBpbiBEYXRhIFZpc3VhbGl6YXRpb24gYWZ0ZXIgbXkgSW50ZXJuc2hpcCBvbiBjcmVhdGluZyBkYXNoYm9hcmRzIHVzaW5nIFN0cmVhbWxpdCBwYWNrYWdlIGluIFB5dGhvbi4gVGhpcyB3YXMgb25lIG9mIHRoZSBrZXkgcmVhc29ucyBmb3IgY29tcGxldGluZyB0aGUgY291cnNlIG9uIFN0YXRpc3RpY2FsIENvbXB1dGluZyBpbiBSIHdoaWNoIGhlbHBlZCBtZSBpbiBsZWFybmluZyBFREEgYW5kIFZpc3VhbGl6YXRpb24gYWxvbmcgd2l0aCBiYXNpY3Mgb2YgSHlwb3RoZXNpcyB0ZXN0aW5nIGluIFIuIA0KDQpJbiB0aGUgbGFzdCB5ZWFycywgSSBoYXZlIGxlYXJuZWQgd29ya2luZyB3aXRoIGRhdGFzZXRzIHdpdGggcXVhbnRpdGF0aXZlIGFuZCBxdWFsaXRhdGl2ZSB2YXJpYWJsZXMuIEhvd2V2ZXIsIHRoaXMgcHJvamVjdCBnYXZlIG1lIGluc2lnaHRzIG9uIHByZWRpY3Rpb24gbW9kZWxsaW5nIGFuZCB0aGUgY2FwYWJpbGl0eSBpdCBkZW1vbnN0cmF0ZXMgaW4gbWFraW5nIHRoZSBhbmFseXNpcyBpbiBiZXR0ZXJpbmcgcGVyc3BlY3RpdmUgb3ZlciB0aGUgZmllbGQgb2YgcmVzZWFyY2guDQoNCjxjZW50ZXI+DQohW1Byb2ZpbGVdKEFtb2doX3BpYy5qcGVnKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCg0KIyMgQXBwZW5kaXgNCg0KYGBge3IgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJywgZXZhbD1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgY29sbGFwc2U9VFJVRX0NCiNMT0FESU5HIFBBQ0tBR0VTDQpsaWJyYXJ5KGRhdGEudGFibGUpICNFbmhhbmNlZCBkYXRhZnJhbWUNCmxpYnJhcnkoY29ycnBsb3QpICAgI0ZvciBwbG90dGluZyBjb3JyZWxhdGlvbiBwbG90DQpsaWJyYXJ5KEdHYWxseSkgICAgICNBbHRlcm5hdGl2ZSBQYWNrYWdlKEFuIEV4dGVuc2lvbikgZm9yIGdncGxvdDINCmxpYnJhcnkodGlkeXZlcnNlKSAgI1BhY2thZ2UgdGhhdCB3ZSBjYW4gdXNlIGZvciBkYXRhIGFuYWx5c2lzDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKSAjIFBhY2thZ2UgZm9yIFBlcmZvcm1hbmNlLCBQcmVkaWN0aW9uIEFuYWx5c2lzDQpsaWJyYXJ5KHBsb3RseSkgI0ZvciBpbXByb3ZpbmcgR3JhcGhpY3Mgb24gcGxvdHMNCmxpYnJhcnkocnN0YXRpeCkgI1BhY2thZ2UgZm9yIHBlcmZvcm1pbmcgc3RhdGlzdGljYWwgdGVzdHMNCg0KIyBEYXRhc2V0IGlzIHJlYWQNCiMjRmlyc3QgZGF0YXNldA0Kc2Vhc29uX3NhbGFyeSA8LSANCiAgcmVhZC5jc3YoIk5CQV9zZWFzb24xNzE4X3NhbGFyeS5jc3YiKQ0Kc2Vhc29uX3NhbGFyeQ0KDQojI1NlY29uZCBkYXRhc2V0DQpwbGF5ZXJfc3RhdHMgPC0gcmVhZC5jc3YoIlNlYXNvbnNfU3RhdHMuY3N2IikNCnBsYXllcl9zdGF0cw0KDQojZGlzcGxheWluZyBkYXRhdHlwZXMgb2YgdmFyaWFibGVzDQojZGF0YXR5cGVzIGZvciBkYXRhc2V0IDENCnN0cihzZWFzb25fc2FsYXJ5KQ0KDQojZGF0YXR5cGVzIGZvciBkYXRhc2V0IDINCnN0cihwbGF5ZXJfc3RhdHMpDQoNCiNGaWx0ZXJpbmcgZGF0YXNldCBmb3IgcmVjZXZpbmcgZGF0YXBvaW50cyBmb3IgdGhlIHllYXI6IDIwMTYuDQojU2VsZWN0aW5nIHJlbGV2YW50IHZhcmlhYmxlcyBsaWtlIFllYXIsIEcsIFBFUiwgRkcsIFBUUyBldGMuDQojTXV0YXRpbmcgY29sdW1ucyBuYW1lZCBNUEcsIFJQRywgUFBHLCBBUEcsIFRPUEcsIEJQRywgU1BHIGZvciBmdXJ0aGVyIGFuYWx5c2lzDQpmaWx0ZXJlZF8yMDE2IDwtIA0KICBwbGF5ZXJfc3RhdHMgJT4lIGZpbHRlcihZZWFyID09IDIwMTYpICU+JSANCiAgc2VsZWN0KFllYXI6RywgTVAsIFBFUiwgRkc6UFRTKSAlPiUgDQogIGRpc3RpbmN0KFBsYXllciwgLmtlZXBfYWxsID0gVFJVRSkgJT4lIA0KICBtdXRhdGUoTVBHID0gTVAvRywgUFBHID0gUFRTL0csIEFQRyA9IEFTVC9HLCANCiAgICAgICAgIFJQRyA9IFRSQi9HLCBUT1BHID0gVE9WL0csIEJQRyA9IEJMSy9HLCANCiAgICAgICAgU1BHID0gU1RML0cpDQoNCiMgUGVyZm9ybWluZyBmdWxsIGpvaW4gdXNpbmcgbWVyZ2UgZnVuY3Rpb24gZm9yIEpvaW5pbmcgZmlsdGVyZWRfMjAxNiBkYXRhc2V0IGFuZCBzZWFzb25fc2FsYXJ5IGRhdGFzZXQgYmFzZWQgb24gY29tbW9uIHZhcmlhYmxlICJQbGF5ZXIiLg0Kc2FsYXJ5X25ldyA8LSBtZXJnZShmaWx0ZXJlZF8yMDE2LCBzZWFzb25fc2FsYXJ5LCBieS54ID0gIlBsYXllciIsIGJ5LnkgPSAiUGxheWVyIikNCiMgUmVuYW1pbmcgYSBjb2x1bW4gZm9yIHNhbGFyeQ0KbmFtZXMoc2FsYXJ5X25ldylbNDBdIDwtICJmaWx0ZXJfc2FsIg0KI0RlbGV0aW5nIHVud2FudGVkIGNvbHVtbg0Kc2FsYXJ5X25ldyA8LSBzYWxhcnlfbmV3Wy0zOV0NCg0KI0dlbmVyYXRpbmcgY29ycmVsYXRpb24gcGxvdCBmb3Igc2FsYXJ5IHdpdGggb3RoZXIgaW5mbHVlbnRpYWwgdmFyaWFibGVzDQojdG8gY2hlY2sgd2hldGhlciB0aGVzZSB2YXJpYWJsZXMgaGF2ZSBjb3JyZWxhdGlvbi4NCmNvcnJwbG90KGNvcihzYWxhcnlfbmV3ICU+JSANCiAgICAgICAgICAgICAgIHNlbGVjdChmaWx0ZXJfc2FsLCBNUEc6U1BHLCANCiAgICAgICAgICAgICAgICAgICAgICBBZ2UsIFBFUiwgY29udGFpbnMoIiUiKSksIA0KICAgICAgICAgICAgIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSwgDQogICAgICAgICBtZXRob2QgPSAibnVtYmVyIix0eXBlID0gInVwcGVyIikNCg0KIyMgUGxvdHRpbmcgc2NhdHRlcnBsb3QgbWF0cml4IGZvciBjb3JyZWxhdGlvbiBmb3IgZmVhdHVyZXMgd2l0aCBzYWxhcnkgdmFyaWFibGVzLg0KIyBNYWRlIHVzZSBvZiBnZ3BhaXJzIGZ1bmN0aW9uLg0KY29yX3NhbGFyeV9uZXcgPC0gDQogIHNhbGFyeV9uZXcgJT4lIA0KICBzZWxlY3QoZmlsdGVyX3NhbCwgUFBHLCBNUEcsIFRPUEcsIFJQRywgUEVSLCBTUEcsIEFQRykNCmdncGFpcnMoY29yX3NhbGFyeV9uZXcpDQoNCiNDb3JyZWxhdGlvbiB0YWJsZQ0KY29yKGNvcl9zYWxhcnlfbmV3KVssImZpbHRlcl9zYWwiXQ0KDQojR2VuZXJhdGlvbiBvZiBJbnRlcmFjdGl2ZSBwbG90IGZvciBwbG90dGluZyBpbmZsdWVuY2Ugb2Ygc2FsYXJ5IHJlY2VpdmVkIGJ5IHRoZSBwbGF5ZXIgb3ZlciBwb2ludHMgc2NvcmVkIHBlciBnYW1lLg0KI3Bsb3RseSBmdW5jdGlvbiBpcyB1c2VkDQojaG92ZXJpbmZvIGFyZ3VtZW50IHByb3ZpZGVzIHVzZWZ1bCB0ZWNobmlxdWUgaW4gZ2VuZXJhdGluZyBhIHBsb3Qgd2l0aCBkeW5hbWljIG5hdHVyZS4gRXh0cmVtZWx5IHVzZWZ1bCBmb3IgcGxvdHRpbmcgcmVhbC10aW1lIGRhdGEuDQpuYW1lcyhzYWxhcnlfbmV3KVs1XSA8LSAiVGVhbSINCnBsb3RfbHkoZGF0YSA9IHNhbGFyeV9uZXcsIHggPSB+ZmlsdGVyX3NhbCwgeSA9IH5QUEcsIGNvbG9yID0gflRlYW0sDQogICAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwNCiAgICAgICAgdGV4dCA9IH5wYXN0ZSgiUGxheWVyOiAiLCBQbGF5ZXIsDQogICAgICAgICAgICAgICAgICAgICAgIjxicj5TYWxhcnk6ICIsIGZvcm1hdChmaWx0ZXJfc2FsLCBiaWcubWFyayA9ICIsIiksIiQiLA0KICAgICAgICAgICAgICAgICAgICAgICI8YnI+UFBHOiAiLCByb3VuZChQUEcsIGRpZ2l0cyA9IDMpLA0KICAgICAgICAgICAgICAgICAgICAgICI8YnI+VGVhbTogIiwgVGVhbSkpICU+JSANCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIlNhbGFyeSB2cyBQb2ludCBQZXIgR2FtZSIsDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlBsYXllcidzIFNhbGFyeSBpbiBVU0QiKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUG9pbnQgcGVyIEdhbWUgZm9yIFBsYXllciIpDQogICkNCg0KI1Bsb3R0aW5nIHNjYXR0ZXJwbG90IG9mIHJlZ3Jlc3Npb24gTW9kZWwgZm9yIHNhbGFyeSB2YXJpYWJsZSBvbiBQb2ludHMgU2NvcmVkIHBlciBHYW1lIHRvIHNlZSB2YXJpYW5jZSBpbiB0aGUgZ3JhcGgNCnNhbGFyeV9uZXcgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBmaWx0ZXJfc2FsLCB5ID0gUFBHKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpDQoNCiNGb3IgZGV0ZXJtaW5pbmcgdGhlIGVmZmVjdCBvZiBUcnVzdCBvbiBUdXJub3ZlcnMuDQojT2J0YWluaW5nIGF2ZXJhZ2UgZm9yIE1QRyBmZWF0dXJlIHVzaW5nIG1lYW4gZnVuY3Rpb24NCmF2Zy5taW51dGVzIDwtIG1lYW4oc2FsYXJ5X3JlZ3Jlc3Npb24kTVBHKQ0KI09idGFpbmluZyBhdmVyYWdlIGZvciBUT1BHIGZlYXR1cmUgdXNpbmcgbWVhbiBmdW5jdGlvbg0KYXZnLnR1cm5vdmVyIDwtIG1lYW4oc2FsYXJ5X3JlZ3Jlc3Npb24kVE9QRykNCiNDb252ZXJ0aW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGludG8gZmFjdG9ycyBmb3IgWWVzIGFuZCBObyB2YWx1ZXMNCnNhbGFyeV9yZWdyZXNzaW9uJFRydXN0ZWQgPC0gYXMuZmFjdG9yKGlmZWxzZShzYWxhcnlfcmVncmVzc2lvbiRNUEcgPj0gYXZnLm1pbnV0ZXMsICJZZXMiLCAiTm8iKSkNCiNDb252ZXJ0aW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGludG8gZmFjdG9ycyBmb3IgWWVzIGFuZCBObyB2YWx1ZXMNCnNhbGFyeV9yZWdyZXNzaW9uJEFncmVzc2l2ZW5lc3MgPC0gYXMuZmFjdG9yKGlmZWxzZShzYWxhcnlfcmVncmVzc2lvbiRUT1BHID49IGF2Zy50dXJub3ZlciwgIlllcyIsICJObyIpKQ0KI1ByaW50aW5nIGZpcnN0IDEwIHJvd3Mgb2YgdGhlIGRhdGFzZXQNCmhlYWQoc2FsYXJ5X3JlZ3Jlc3Npb24pDQoNCiMgR2VuZXJhdGluZyByZWdyZXNzaW9uIHBsb3QgdG8gZGV0ZXJtaW5lIGFueSBkaWZmZXJlbmNlIGluIHNhbGFyeSBiYXNlZCBvbiBBZ3Jlc3NpdmVuZXNzDQpzYWxhcnlfcmVncmVzc2lvbiAlPiUgDQogIGdncGxvdChhZXMoeCA9IGZpbHRlcl9zYWwsIHkgPSBQUEcsIGNvbG91ciA9IEFncmVzc2l2ZW5lc3MpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpDQoNCiNHZXR0aW5nIGF2ZXJhZ2UgcGxheWVyJ3Mgc2FsYXJ5IGJ5IGZpbmRpbmcgdGhlIG1lYW4gZm9yIGFsbCBwbGF5ZXJzDQptZWFuX3NhbGFyeSA8LSBtZWFuKHNhbGFyeV9yZWdyZXNzaW9uJGZpbHRlcl9zYWwpDQptZWFuX3NhbGFyeQ0KDQojRml0dGluZyBhIG11bHRpcGxlIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIHNhbGFyeSBiYXNlZCBvbiBUcnVzdGVkIGFuZCBBZ3Jlc3NpdmVuZXNzDQp0cnVzdF9sbSA8LSBsbShmb3JtdWxhID0gZmlsdGVyX3NhbCB+IFRydXN0ZWQgKiBBZ3Jlc3NpdmVuZXNzLCBkYXRhPXNhbGFyeV9yZWdyZXNzaW9uKQ0KI1Bsb3R0aW5nIHN1bW1hcnkgdGFibGUgZm9yIG91ciByZWdyZXNzaW9uIG1vZGVsDQpzdW1tYXJ5KHRydXN0X2xtKQ0KDQojIENvZWZmaWNpZW50cyBUYWJsZQ0KY29lZih0cnVzdF9sbSkNCg0KI0J1aWxkaW5nIGEgcHJlZGljdGlvbiBmdW5jdGlvbiBmb3IgcHJlZGljdGluZyB2YWx1ZSBiYXNlZCBvbiBQUEcsIE1QRywgVE9QRy4NCiMgUHJpbnRpbmcgb3V0cHV0IHZhbHVlIGZvciBvdXIgZnVuY3Rpb24NCnNhbGFyeV9wcmVkaWN0aW9uIDwtIGZ1bmN0aW9uKG0sIHBvaW50LCBtaW51dGVzLCB0dXJuX292ZXIpew0KICBwcmVfbmV3IDwtIHByZWRpY3QobSwgZGF0YS5mcmFtZShQUEcgPSBwb2ludCwgTVBHID0gbWludXRlcywgVE9QRyA9IHR1cm5fb3ZlcikpDQogIG1zZyA8LSBwYXN0ZSgiUFBHOiIsIHBvaW50LCAiLE1QRzoiLCBtaW51dGVzLCAiLFRPUEc6IiwgdHVybl9vdmVyLCAiID09PiBFeHBlY3RlZCBTYWxhcnkgZm9yIHBsYXllcjogJCIsIGZvcm1hdChyb3VuZChwcmVfbmV3KSwgYmlnLm1hcmsgPSAiLCIpLCBzZXAgPSAiIikNCiAgcHJpbnQobXNnKQ0KfQ0KDQojIEZpdHRpbmcgdmFsdWVzIGZvciBvYnRhaW5pbmcgb3V0cHV0DQptb2RlbCA8LSBsbShmb3JtdWxhID0gZmlsdGVyX3NhbCB+IFBQRyArIE1QRyArIFRPUEcsIGRhdGEgPSBzYWxhcnlfcmVncmVzc2lvbikNCnNhbGFyeV9wcmVkaWN0aW9uKG1vZGVsLCAzMS42LCAzNC42LCA1LjQpDQpgYGANCg0KIyMgQWNrbm93bGVkZ2VtZW50DQoNCiogX19DbGVtc29uIFVuaXZlcnNpdHkgU2Nob29sIG9mIENvbXB1dGluZ19fLg0KDQoqIF9fUHJvZi4gRWxsZW4gQnJlYXplbCwgVGVhY2hlciBpbiBTVEFULTYwMjAgSW50cm8gdG8gU3RhdGlzdGljYWwgQ29tcHV0aW5nIC0gU3ByaW5nIDIwMjIgYXQgQ2xlbXNvbiBVbml2ZXJzaXR5X18uDQoNCg==